package org.example.study.JUC.CompletableFuture;

import java.util.concurrent.*;

public class CompletableFutureTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        ExecutorService defaltExecutor = Executors.newFixedThreadPool(10);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 60, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(20));

        // 创建异步任务
        // 无返回值 可以添加第二个参数，用于自定义线程池
        CompletableFuture<Void> cf1 = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread() + "无返回值       do something....");
        });

        // 有返回值 可以添加第二个参数，用于自定义线程池
        CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "有返回值       do something....");
            return 1;
        });

        // 异步回调
        // thenApply 某个任务执行完成后执行的回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,带有返回值.  子任务与父任务使用的是同一个线程
        CompletableFuture<Integer> cf3 = cf2.thenApply((result)-> {
            System.out.println(Thread.currentThread() + "thenApply       do something....");
            return result + 1;
        });

        //thenApplyAsync 某个任务执行完成后执行的回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,带有返回值. 子任务与父任务使用不同的线程
        CompletableFuture<Integer> cf4 = cf2.thenApplyAsync((result)-> {
            System.out.println(Thread.currentThread() + "thenApplyAsync       do something....");
            return result + 1;
        });

        //thenAccept 某个任务执行完成后执行的回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,无返回值. 子任务与父任务使用同一个线程
        CompletableFuture<Void> cf5 = cf2.thenAccept((result)-> {
            System.out.println(Thread.currentThread() + "thenAccept       do something....");
            System.out.println("结果->" + result+ 1);
        });

        //thenAcceptAsync 某个任务执行完成后执行的回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,无返回值. 子任务与父任务使用不同的线程
        CompletableFuture<Void> cf6 = cf2.thenAcceptAsync((result)-> {
            System.out.println(Thread.currentThread() + "thenAcceptAsync       do something....");
            System.out.println("结果->" + result+ 1);
        });

        //thenRun 某个任务执行完成后执行的回调方法,不会将任务的执行结果作为入参传递到回调方法中,无返回值. 子任务与父任务使用同一个线程
        CompletableFuture<Void> cf7 = cf2.thenRun(() -> {
            System.out.println(Thread.currentThread() + "thenRun       do something....");
        });

        //thenRunAsync 某个任务执行完成后执行的回调方法,不会将任务的执行结果作为入参传递到回调方法中,无返回值. 子任务与父任务使用不同的线程
        CompletableFuture<Void> cf8 = cf2.thenRunAsync(() -> {
            System.out.println(Thread.currentThread() + "thenRunAsync       do something....");
        });

        //whenComplete 某个任务执行完成后执行的回调方法,会将任务的执行结果作为入参传递到回调方法中,会将当前任务执行结果或者执行期间抛出的异常传递给回调方法,正常？ null：异常. 子任务与父任务使用同一个线程
        CompletableFuture<Integer> cf9 = cf2.whenComplete((result, e)-> {
            System.out.println(Thread.currentThread() + "whenComplete       do something....");
            System.out.println("上个任务结果：" + result);
            System.out.println("上个任务抛出异常：" + e);
        });

        //whenCompleteAsync 某个任务执行完成后执行的回调方法,会将任务的执行结果作为入参传递到回调方法中,会将当前任务执行结果或者执行期间抛出的异常传递给回调方法,正常？ null：异常. 子任务与父任务使用不同的线程
        CompletableFuture<Integer> cf10 = cf2.whenCompleteAsync((result, e)-> {
            System.out.println(Thread.currentThread() + "whenCompleteAsync       do something....");
            System.out.println("上个任务结果：" + result);
            System.out.println("上个任务抛出异常：" + e);
        });

        //handle 跟whenComplete基本一致，区别在于handle的回调方法有返回值。
        CompletableFuture<Integer> cf11 = cf2.handle((result, e)-> {
            System.out.println(Thread.currentThread() + "handle       do something....");
            System.out.println("上个任务结果：" + result);
            System.out.println("上个任务抛出异常：" + e);
            return result + 1;
        });

        //handleAsync 跟whenCompleteAsync基本一致，区别在于handle的回调方法有返回值。子任务与父任务使用不同的线程
        CompletableFuture<Integer> cf12 = cf2.handleAsync((result, e)-> {
            System.out.println(Thread.currentThread() + "handleAsync       do something....");
            System.out.println("上个任务结果：" + result);
            return result + 1;
        });

        //thenCombine、thenAcceptBoth 和runAfterBoth
        /**
         * 区别：thenCombine会将两个任务的执行结果作为所提供函数的参数，且该方法有返回值；
         * thenAcceptBoth同样将两个任务的执行结果作为方法入参，但是无返回值；
         * runAfterBoth没有入参，也没有返回值。注意两个任务中只要有一个执行异常，则将该异常信息作为指定任务的执行结果
         */

        //applyToEither、acceptEither和runAfterEither
        /**
         * 这三个方法和上面一样也是将两个CompletableFuture组合起来处理，当有一个任务正常完成时，就会进行下阶段任务。
         * 区别：
         * applyToEither会将已经完成任务的执行结果作为所提供函数的参数，且该方法有返回值；
         * acceptEither同样将已经完成任务的执行结果作为方法入参，但是无返回值；
         * runAfterEither没有入参，也没有返回值。
         */

        //allOf / anyOf
        /**
         * allOf：CompletableFuture是多个任务都执行完成后才会执行，只有有一个任务执行异常，则返回的CompletableFuture执行get方法时会抛出异常，如果都是正常执行，则get返回null。
         * anyOf ：CompletableFuture是多个任务只要有一个任务执行完成，则返回的CompletableFuture执行get方法时会抛出异常，如果都是正常执行，则get返回执行完成任务的结果
         */
        //等待任务执行完成
        System.out.println("结果->" + cf1.get());
        System.out.println("结果->" + cf2.get());
        System.out.println("结果->" + cf3.get());
        System.out.println("结果->" + cf4.get());
        System.out.println("结果->" + cf5.get());
        System.out.println("结果->" + cf6.get());
        System.out.println("结果->" + cf7.get());
        System.out.println("结果->" + cf8.get());
        System.out.println("结果->" + cf9.get());
        System.out.println("结果->" + cf10.get());
        System.out.println("结果->" + cf11.get());
        System.out.println("结果->" + cf12.get());
    }
}
